#include <private/qobject_p.h>
#include <QMetaMethod>
#include <QObject>
#include "ROSignalConnection.h"

class DxSOPropertyObserver:public QtPrivate::QSlotObjectBase
{
public:
    DxSOPropertyObserver():QtPrivate::QSlotObjectBase(&DxSOPropertyObserver::FuncImpl){

    }
    static void FuncImpl(int which, QSlotObjectBase* this_, QObject *receiver, void **args, bool *ret){
        auto This = static_cast<DxSOPropertyObserver*>(this_);

        if(which == QtPrivate::QSlotObjectBase::Operation::Call)
        {
            This->func(args);
        }
        else if(which == QtPrivate::QSlotObjectBase::Compare)
        {
            *ret = false;
        }
        else if(which == QtPrivate::QSlotObjectBase::Destroy)
        {
            delete This;
        }
    }

    std::function<void(void** param)> func;
};

QMetaObject::Connection ROSignalConnection::SlotInfo::on(const std::function<void (void **)>& func,Qt::ConnectionType type)
{
    if(signalInfo.obj == nullptr)
    {
        return {};
    }

    if(slotobj == nullptr)
    {
        slotobj = signalInfo.obj;
    }

    DxSOPropertyObserver* sob = new DxSOPropertyObserver();

    sob->func = func;

    return QObjectPrivate::connect(signalInfo.obj,signalInfo.signal,slotobj,sob,type);
}

QMetaObject::Connection ROSignalConnection::SlotInfo::onVarList(std::function<void (const QVariantList &)> func,Qt::ConnectionType type)
{
    if(signalInfo.obj == nullptr)
    {
        return {};
    }

    auto meta = signalInfo.obj->metaObject();
    auto method = meta->method(signalInfo.signal);

    return on([=](void** param)->void{
        QVariantList varParams;
        int pcount = method.parameterCount();
        for(int i = 0;i<pcount;i++)
        {
            auto pType = method.parameterMetaType(pcount);
            varParams<<QVariant(pType,param[i + 1]);
        }

        func(varParams);
    },type);
}

bool ROSignalConnection::SlotInfo::compareTypes(const QList<int> &signalTypes, const QList<int> &slotTypes)
{
    if(slotTypes.size() > signalTypes.size())
    {
        return false;
    }
    for(int i = 0;i<slotTypes.size();i++)
    {
        if(slotTypes[i] != signalTypes[i])
        {
            return false;
        }
    }
    return true;
}

QList<int> ROSignalConnection::SlotInfo::getSignalTypeIds()
{
    QList<int> ret;
    if(signalInfo.obj == nullptr)
    {
        return {};
    }
    auto meta = signalInfo.obj->metaObject();
    auto method = meta->method(signalInfo.signal);
    int pcount = method.parameterCount();
    for(int i = 0;i<pcount;i++)
    {
        ret << method.parameterType(pcount);
    }

    return ret;
}

ROSignalConnection::SlotInfo ROSignalConnection::SignalInfo::to(QObject *obj)
{
    ROSignalConnection::SlotInfo ret;

    ret.signalInfo = *this;
    ret.slotobj = obj;

    return ret;
}

ROSignalConnection::SlotInfo ROSignalConnection::SignalInfo::to()
{
    return to(obj);
}

ROSignalConnection::SignalInfo::SignalInfo()
{

}


ROSignalConnection::SignalInfo ROSignalConnection::connect(QObject *obj, int signal)
{
    SignalInfo ret;

    ret.signal = signal;
    ret.obj = obj;

    return ret;
}

ROSignalConnection::SignalInfo ROSignalConnection::connect(QObject *obj, QMetaMethod signal)
{
    if(signal.isValid())
    {
        qDebug()<<"signal is not valid";
        return {};
    }

    return connect(obj,signal.methodIndex());
}
